/* Copyright 2015 Esri
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.esri.arcgis.android.samples.standardlicenseoffline;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.os.Bundle;
import android.os.Environment;
import android.widget.FrameLayout;

import com.esri.android.map.MapOptions;
import com.esri.android.map.MapOptions.MapType;
import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISLocalTiledLayer;
import com.esri.android.oauth.OAuthView;
import com.esri.android.runtime.ArcGISRuntime;
import com.esri.core.io.UserCredentials;
import com.esri.core.map.CallbackListener;
import com.esri.core.portal.LicenseInfo;
import com.esri.core.portal.Portal;
import com.esri.core.portal.PortalInfo;
import com.esri.core.runtime.LicenseLevel;
import com.esri.core.runtime.LicenseResult;

public class MainActivity extends Activity {

    private static final String CLIENT_ID               = "pqN3y96tSb1j8ZAY";

    private static final String PORTAL_URL              = "https://www.arcgis.com/";

    private static final String LICENSE_INFO_FILE_NAME  = "licenseinfo.json";

    private static final String DATA_RELATIVE_PATH      = "/SanFrancisco.tpk";

    private static final int OAUTH_EXPIRATION_NEVER     = -1;

    public FrameLayout mViewContainer;

    public OAuthView mOAuthView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mViewContainer = (FrameLayout) findViewById(R.id.main_activity_view_container);


        LicenseResult licenseResult = ArcGISRuntime.setClientId(CLIENT_ID);

        LicenseLevel licenseLevel = ArcGISRuntime.License.getLicenseLevel();
        if (licenseResult == LicenseResult.VALID && licenseLevel == LicenseLevel.BASIC) {
            initializeStandardLicense();
        } else {

            MessageDialogFragment.showMessage(getString(R.string.valid_client_id_required), getFragmentManager());

            showMap();
        }
    }

    /**
     * This method chooses how to set the app license by checking network
     * connectivity. Results are reported to the user.
     */
    private void initializeStandardLicense() {
        // 有网络
        if (isNetworkAvailable()) {
            signInWithOAuth();
        }
        // 无网络
        else {
            // 读取本地
            LicenseInfo licenseInfo = null;
            try {
                licenseInfo = readLicenseInfoFromFileSystem();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // Use the deserialized LicenseInfo to set the app license. If the
            // LicenseInfo is null, the return value will be INVALID.
            LicenseResult licenseResult = ArcGISRuntime.License.setLicense(licenseInfo);

            // Check and report the result of the licensing.
            LicenseLevel licenseLevel = ArcGISRuntime.License.getLicenseLevel();
            if (licenseResult == LicenseResult.VALID && licenseLevel == LicenseLevel.STANDARD) {
                MessageDialogFragment.showMessage(getString(R.string.standard_license_succeeded), getFragmentManager());
            } else {
                MessageDialogFragment.showMessage(getString(R.string.standard_license_requires_connection), getFragmentManager());
            }

            // Now licensing is complete, create and show a MapView.
            showMap();
        }
    }

    /**
     * This method attempts to set the license level of the application to
     * LicenseLevel.Standard. Standard license level is set by retrieving a
     * LicenseInfo object from an authenticated Portal instance. The authenticated
     * Portal instance is created with the UserCredentials obtained from the
     * previous OAuth sign in step. The steps to set standard license level with a
     * LicenseInfo object are:
     * <ol>
     * <li>Sign in to a portal via OAuth to retrieve UserCredentials.</li>
     * <li>Create an authenticated Portal instance from the UserCredentials.</li>
     * <li>Fetch the PortalInfo from the Portal instance and retrieve the
     * LicenseInfo.</li>
     * <li>Initialize the license with the LicenseInfo to activate Standard
     * license level.</li>
     * </ol>
     */
    public void setStandardLicenseFromPortal(UserCredentials credentials) {

        // Create a Portal object with the credentials from the OAuthView.
        Portal portal = new Portal(PORTAL_URL, credentials);
        PortalInfo portalInfo = null;

        // Get the PortalInfo from the Portal.
        try {
            portalInfo = portal.fetchPortalInfo();
        } catch (Exception e) {
            MessageDialogFragment.showMessage(getString(R.string.standard_license_failed), getFragmentManager());

            return;
        }
        LicenseInfo licenseInfo     = portalInfo.getLicenseInfo();
        // Set app license with the LicenseInfo from the PortalInfo.
        LicenseResult licenseResult = ArcGISRuntime.License.setLicense(licenseInfo);
        // Check and report the result of the licensing.
        LicenseLevel licenseLevel   = ArcGISRuntime.License.getLicenseLevel();

        if (licenseResult == LicenseResult.VALID && licenseLevel == LicenseLevel.STANDARD) {

            // Store the LicenseInfo on the file system so it can be used another time
            // when there is no network connectivity.
            try {
                writeLicenseInfoToFileSystem(licenseInfo);
            } catch (IOException e) {
                e.printStackTrace();
            }
            MessageDialogFragment.showMessage(getString(R.string.standard_license_succeeded), getFragmentManager());
        } else {
            MessageDialogFragment.showMessage(getString(R.string.standard_license_failed), getFragmentManager());
        }

        showMap();
    }

    // 检查网络是否可用
    public boolean isNetworkAvailable() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        // Check cellular data connection.
        NetworkInfo mobileNi = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        if (mobileNi != null && mobileNi.getState() == State.CONNECTED) {
            return true;
        }

        // Check wifi connection
        NetworkInfo wifiNi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        if (wifiNi != null && wifiNi.getState() == State.CONNECTED) {
            return true;
        }

        return false;
    }

    /**
     * Sets up a sign in UI that allows the user to sign in to a portal via OAuth.
     * OAuth is the recommended authentication method to sign in to a portal.
     * After successful sign in the obtained UserCredentials are used to set the
     * license level to standard by retrieving a LicenseInfo object from an
     * authenticated Portal instance (see setStandardLicenseWithLicenseInfo()
     * method).
     */
    private void signInWithOAuth() {

        // Create a new OAuthView to allow users to enter credentials.
        mOAuthView = new OAuthView(this, PORTAL_URL, CLIENT_ID, OAUTH_EXPIRATION_NEVER, new CallbackListener<UserCredentials>() {

            @Override
            public void onError(Throwable e) {
                MessageDialogFragment.showMessage(getString(R.string.oauth_login_failed), getFragmentManager());
            }

            @Override
            public void onCallback(UserCredentials credentials) {

                // Use the entered credentials to get a license.
                if (credentials != null) {
                    setStandardLicenseFromPortal(credentials);
                } else {
                    MessageDialogFragment.showMessage(getString(R.string.oauth_login_failed), getFragmentManager());
                }
            }
        });

        // Add the OAuthView to the root view.
        mViewContainer.addView(mOAuthView);
    }

    /**
     * Attempts to read a LicenseInfo persisted as a json string to a private
     * file.
     *
     * @return a LicenseInfo read from the file system or null
     * @throws IOException
     */
    private LicenseInfo readLicenseInfoFromFileSystem() throws IOException {

        LicenseInfo licenseInfo = null;
        BufferedReader reader = null;

        try {
            // Open and read the saved license info.
            InputStream in              = this.openFileInput(LICENSE_INFO_FILE_NAME);
            reader                      = new BufferedReader(new InputStreamReader(in));
            StringBuilder jsonBuilder   = new StringBuilder();
            String line = null;

            while ((line = reader.readLine()) != null) {
                jsonBuilder.append(line);
            }

            // Deserialize the json string from the file into a LicenseInfo object
            licenseInfo = LicenseInfo.fromJson(jsonBuilder.toString());

        } catch (FileNotFoundException e) {
            // no persisted license info available
        } finally {
            // Clean up the license file reader.
            if (reader != null) {
                reader.close();
            }
        }

        return licenseInfo;
    }

    /** Writes the specified LicenseInfo as a json string to the file system. **/

    private void writeLicenseInfoToFileSystem(LicenseInfo licenseInfo) throws IOException {

        if (licenseInfo == null) {
            return;
        }

        // Write serialized LicenseInfo json to a private file.
        Writer writer = null;
        try {
            OutputStream out = this.openFileOutput(LICENSE_INFO_FILE_NAME, Context.MODE_PRIVATE);
            writer = new OutputStreamWriter(out);
            writer.write(licenseInfo.toJson());
        } finally {
            // Clean up the license file writer.
            if (writer != null) {
                writer.close();
            }
        }

    }

    private void showMap() {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                // If the OAuthView was used, remove it so map can be shown instead.
                if (mOAuthView != null) {
                    mViewContainer.removeView(mOAuthView);
                    mOAuthView = null;
                }

                MapView mapView;
                if (isNetworkAvailable()) {
                    // 有网络
                    mapView = new MapView(MainActivity.this, new MapOptions(MapType.TOPO, 34.056215, -117.195668, 16));
                } else {
                    // 无网络 加载tpk离线地图
                    String dataPath = Environment.getExternalStorageDirectory().getPath() + DATA_RELATIVE_PATH;
                    if (!new File(dataPath).exists()) {
                        MessageDialogFragment.showMessage(getString(R.string.local_data_not_found) + dataPath,getFragmentManager());
                    }
                    ArcGISLocalTiledLayer local = new ArcGISLocalTiledLayer(dataPath);

                    // Create a MapView, using extent and spatial reference of the layer.
                    mapView = new MapView(MainActivity.this, local.getSpatialReference(), local.getFullExtent());
                    mapView.addLayer(local);
                }

                // Add the MapView to the ViewContainer.
                mViewContainer.addView(mapView);
            }
        });
    }

}
